package com.wontube.client.extension.utils.net;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wontube.client.conf.ServerEnvironment;
import com.wontube.client.extension.utils.StringUtils;

/**
 * @author: yuechao
 * 
 */
public final class URLUtils {
	private static final Logger logger = LoggerFactory.getLogger(URLUtils.class);

	private URLUtils() {
	}

	/**
	 * 
	 * Description:取得当前类所在的文件
	 * 
	 * @param clazz
	 * @return
	 */
	public static File getClassFile(Class<?> clazz) {
		URL path = clazz.getResource(clazz.getName().substring(clazz.getName().lastIndexOf(".") + 1) + ".class");
		if (path == null) {
			String name = clazz.getName().replaceAll("[.]", "/");
			path = clazz.getResource("/" + name + ".class");
		}
		return new File(path.getFile());
	}

	/**
	 * 
	 * Description:同getClassFile 解决中文编码问题
	 * 
	 * @param clazz
	 * @return
	 */
	public static String getClassFilePath(Class<?> clazz) {
		try {
			return URLDecoder.decode(getClassFile(clazz).getAbsolutePath(), ServerEnvironment.charsetName);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.toString());
		}

		return "";
	}

	/**
	 * 
	 * Description:取得当前类所在的ClassPath目录
	 * 
	 * @param clazz
	 * @return
	 */
	public static File getClassPathFile(Class<?> clazz) {
		File file = getClassFile(clazz);
		for (int i = 0, count = clazz.getName().split("[.]").length; i < count; i++) {
			file = file.getParentFile();
		}

		if (file.getName().toUpperCase().endsWith(".JAR!")) {
			file = file.getParentFile();
		}

		return file;
	}

	/**
	 * 获取jar包路径
	 * 
	 * @param clazz
	 * @return
	 */
	public static String getJarOrClassFile(Class<?> clazz) {
		File file = getClassFile(clazz);
		int count = clazz.getName().split("[.]").length;
		for (int i = 0; i < count; i++) {
			file = file.getParentFile();
		}

		boolean isInJarFile = file.getAbsolutePath().toUpperCase().endsWith(".JAR!");
		if (isInJarFile) {
			String filename = file.getPath();
			if (filename.startsWith("file:")) {
				filename = filename.substring("file:".length());
				// windows
				if (filename.startsWith("\\")) {
					filename = filename.substring(1);
				}
			}
			filename = filename.substring(0, filename.length() - 1);
			return filename;
		}

		return getClassFilePath(clazz);
	}

	/**
	 * 
	 * Description: 同getClassPathFile 解决中文编码问题
	 * 
	 * @param clazz
	 * @return
	 */
	public static String getClassPath(Class<?> clazz) {
		try {
			return java.net.URLDecoder.decode(getClassPathFile(clazz).getAbsolutePath(), ServerEnvironment.charsetName);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.toString());
		}

		return "";
	}

	public static Map<String, String> parseQueryString(String queryString) {
		Map<String, String> map = new HashMap<String, String>();
		if (StringUtils.isNullOrEmpty(queryString)) {
			return map;
		}

		int index = queryString.indexOf('?') + 1;
		if (index >= 0) {
			queryString = queryString.substring(index);
		}

		StringBuilder sbValue = new StringBuilder();
		String key = "";
		for (index = 0; index < queryString.length(); index++) {
			char ch = queryString.charAt(index);
			if (ch == '=') {
				if (sbValue.length() > 0) {
					key = sbValue.toString();
					sbValue = new StringBuilder();
				}
			} else if (ch == '&') {
				if (!"".equals(key)) {
					map.put(key, sbValue.toString());
				}
				sbValue = new StringBuilder();
			} else {
				sbValue.append(ch);
			}
		}

		if (sbValue.length() > 0) {
			map.put(key, sbValue.toString());
		}

		return map;
	}

	/**
	 * 检查url是否已失效
	 * 
	 * @param url
	 * @return
	 */
	public static boolean checkUrl(String url) {
		URL uri;

		try {
			uri = new URL(url);
		} catch (MalformedURLException e) {
			return false;
		}
		
		HttpURLConnection conn = null;
		try {
			conn = (HttpURLConnection) uri.openConnection();
			conn.setRequestMethod("HEAD");
			conn.setConnectTimeout(5000);
			conn.connect();
			return (conn.getResponseCode() == HttpURLConnection.HTTP_OK
					|| conn.getResponseCode() == HttpURLConnection.HTTP_PARTIAL);
		} catch (IOException e) {
			// 网络问题，认为合法
			return true;
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}
	}
	
	private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()";

	public static String encodeURIComponent(String input) {
		if (input == null || "".equals(input)) {
			return input;
		}

		int l = input.length();
		StringBuilder o = new StringBuilder(l * 3);
		try {
			for (int i = 0; i < l; i++) {
				String e = input.substring(i, i + 1);
				if (ALLOWED_CHARS.indexOf(e) == -1) {
					byte[] b = e.getBytes(ServerEnvironment.charsetName);
					o.append(getHex(b));
					continue;
				}
				o.append(e);
			}
			return o.toString();
		} catch (UnsupportedEncodingException e) {
			logger.error(e.toString());
		}

		return input;
	}

	private static String getHex(byte buf[]) {
		StringBuilder o = new StringBuilder(buf.length * 3);
		for (int i = 0; i < buf.length; i++) {
			int n = (int) buf[i] & 0xff;
			o.append("%");
			if (n < 0x10) {
				o.append("0");
			}
			o.append(Long.toString(n, 16).toUpperCase());
		}
		return o.toString();
	}

	public static String decodeURIComponent(String encodedURI) {
		char actualChar;

		StringBuffer buffer = new StringBuffer();

		int bytePattern, sumb = 0;

		for (int i = 0, more = -1; i < encodedURI.length(); i++) {
			actualChar = encodedURI.charAt(i);

			switch (actualChar) {
			case '%': {
				actualChar = encodedURI.charAt(++i);
				int hb = (Character.isDigit(actualChar) ? actualChar - '0'
						: 10 + Character.toLowerCase(actualChar) - 'a') & 0xF;
				actualChar = encodedURI.charAt(++i);
				int lb = (Character.isDigit(actualChar) ? actualChar - '0'
						: 10 + Character.toLowerCase(actualChar) - 'a') & 0xF;
				bytePattern = (hb << 4) | lb;
				break;
			}
			case '+': {
				bytePattern = ' ';
				break;
			}
			default: {
				bytePattern = actualChar;
			}
			}

			if ((bytePattern & 0xc0) == 0x80) { // 10xxxxxx
				sumb = (sumb << 6) | (bytePattern & 0x3f);
				if (--more == 0)
					buffer.append((char) sumb);
			} else if ((bytePattern & 0x80) == 0x00) { // 0xxxxxxx
				buffer.append((char) bytePattern);
			} else if ((bytePattern & 0xe0) == 0xc0) { // 110xxxxx
				sumb = bytePattern & 0x1f;
				more = 1;
			} else if ((bytePattern & 0xf0) == 0xe0) { // 1110xxxx
				sumb = bytePattern & 0x0f;
				more = 2;
			} else if ((bytePattern & 0xf8) == 0xf0) { // 11110xxx
				sumb = bytePattern & 0x07;
				more = 3;
			} else if ((bytePattern & 0xfc) == 0xf8) { // 111110xx
				sumb = bytePattern & 0x03;
				more = 4;
			} else { // 1111110x
				sumb = bytePattern & 0x01;
				more = 5;
			}
		}
		return buffer.toString();
	}

	public static StringBuilder downloadHtml(String url) {
		StringBuilder sb = new StringBuilder();
		URL uri;
		try {
			uri = new URL(url);
		} catch (MalformedURLException e) {
			logger.error(e.toString());
			return sb;
		}

		try {
			HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
			conn.connect();
			InputStream in = conn.getInputStream();
			InputStreamReader reader = new InputStreamReader(in, ServerEnvironment.charsetName);
			try {
				char[] cbuffer = new char[1024];
				while (true) {
					int len = reader.read(cbuffer, 0, cbuffer.length);
					if (len <= 0) {
						break;
					}
					sb.append(cbuffer, 0, len);
				}
			} finally {
				in.close();
				reader.close();
				conn.disconnect();
			}
		} catch (IOException e) {
			logger.error(e.toString());
		}

		return sb;
	}
}